package com.intelli4.pos.controllers.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;

import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.transaction.annotation.Transactional;

import com.intelli4.pos.controllers.OrderController;
import com.intelli4.pos.controllers.OrderEventManager;
import com.intelli4.pos.core.Operator;
import com.intelli4.pos.core.Order;
import com.intelli4.pos.core.OrderItem;
import com.intelli4.pos.core.OrderStatus;
import com.intelli4.pos.core.Payment;
import com.intelli4.pos.core.Session;
import com.intelli4.pos.core.TaxItem;
import com.intelli4.pos.core.Terminal;
import com.intelli4.pos.events.AfterOrderCancelEvent;
import com.intelli4.pos.events.AfterOrderCompleteEvent;
import com.intelli4.pos.events.AfterOrderNewEvent;
import com.intelli4.pos.events.AfterOrderResumeEvent;
import com.intelli4.pos.events.AfterOrderSuspendEvent;
import com.intelli4.pos.events.BeforeOrderCancelEvent;
import com.intelli4.pos.events.BeforeOrderCompleteEvent;
import com.intelli4.pos.events.BeforeOrderResumeEvent;
import com.intelli4.pos.events.BeforeOrderSuspendEvent;

public class OrderControllerImpl extends HibernateDaoSupport implements
		OrderController {
	private OrderEventManager eventManager;
	
	private List<Order> suspendedOrders = new ArrayList<Order>();

	@Override
	public void setEventManager(OrderEventManager eventManager) {
		this.eventManager = eventManager;
	}

	@Override
	public Order create(Session session) {
		Order order = new Order();
		// TODO: implement an order number generator that creates unique numbers
		// using Operator ID, Terminal ID & Current Time in Millis
		order.setId("T" + System.currentTimeMillis());
		order.setSession(session);
		order.setShiftName(session.getShift().getName());
		order.setStartTime(Calendar.getInstance());

		// Populate operator info
		Operator operator = session.getOperator();
		order.setOperator(operator);
		order.setOperatorEmpId(operator.getEmpId());
		order.setOperatorFirstName(operator.getFirstName());
		order.setOperatorLastName(operator.getLastName());

		// Populate terminal info
		Terminal terminal = session.getTerminal();
		order.setTerminal(terminal);
		order.setTerminalName(terminal.getName());

		// Populate other order info
		order.setOrderItems(new ArrayList<OrderItem>());
		order.setTaxItems(new ArrayList<TaxItem>());
		order.setPayments(new ArrayList<Payment>());
		order.setSubtotal(new BigDecimal(0));
		order.setTotal(new BigDecimal(0));

		order.setStatus(OrderStatus.NEW);

		// Fire the event
		eventManager.fireEvent(new AfterOrderNewEvent(order));

		return order;
	}

	@Override
	public void suspend(Order order) {
		if (!eventManager.fireEvent(new BeforeOrderSuspendEvent(order)))
			return;

		order.setStatus(OrderStatus.SUSPENDED);
		suspendedOrders.add(order);

		eventManager.fireEvent(new AfterOrderSuspendEvent(order));
	}

	@Override
	public void resume(Order order) {
		if (!eventManager.fireEvent(new BeforeOrderResumeEvent(order)))
			return;

		order.setStatus(OrderStatus.RESUMED);
		suspendedOrders.remove(order);

		eventManager.fireEvent(new AfterOrderResumeEvent(order));
	}

	@Override
	@Transactional
	public void complete(Order order) {
		if (!eventManager.fireEvent(new BeforeOrderCompleteEvent(order)))
			return;

		order.setStatus(OrderStatus.COMPLETED);
		order.setEndTime(Calendar.getInstance());

		getHibernateTemplate().save(order);
		
		eventManager.fireEvent(new AfterOrderCompleteEvent(order));
	}

	@Override
	@Transactional
	public void cancel(Order order) {
		if (!eventManager.fireEvent(new BeforeOrderCancelEvent(order)))
			return;

		order.setStatus(OrderStatus.CANCELLED);
		order.setEndTime(Calendar.getInstance());

		getHibernateTemplate().save(order);
		
		eventManager.fireEvent(new AfterOrderCancelEvent(order));
	}

	@Override
	public List<Order> listSuspended() {
		return suspendedOrders;
	}
}
